﻿using ICSharpCode.SharpZipLib.Zip;
using Learun.Application.Base.SystemModule;
using Learun.Application.Organization;
using Learun.Util;
using Microsoft.Win32;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using static Learun.Application.TwoDevelopment.ZZDT_EC.ProjectSugar;
using static Learun.Util.SqlSugar.SqlSugarHelper;

namespace Learun.Application.TwoDevelopment.ZZDT_EC
{
    /// <summary>
    /// 版 本 PIT-ADMS V7.0.3 敏捷开发框架
    /// Copyright (c) 2013-2018 Hexagon PPM
    /// 创 建：超级管理员
    /// 日 期：2022-03-03 17:00
    /// 描 述：元件库文件表
    /// </summary>
    public class ec_library_fileBLL : ec_library_fileIBLL
    {
        private ec_library_fileService ec_library_fileService = new ec_library_fileService();

        #region 获取数据
        /// <summary>
        /// 获取页面显示列表数据
        /// <summary>
        /// <param name="queryJson">查询参数</param>
        /// <returns></returns>
        public IEnumerable<ec_library_fileEntity> GetList(string queryJson, Pagination pagination = null)
        {
            try
            {
                var queryParam = queryJson.ToJObject();
                var ProjectId = queryParam["ProjectId"]?.ToString();
                var LibraryFileName = queryParam["LibraryFileName"]?.ToString();
                var LibraryCatalogueID = queryParam["LibraryCatalogueID"]?.ToString();
                var LibraryFileNameFull = queryParam["LibraryFileNameFull"]?.ToString();
                var ObjectTypeID = queryParam["ObjectTypeID"]?.ToString();

                var tableName = TableName<ec_library_fileEntity>(ProjectId);
                var libTableName = TableName<ec_objecttypelibEntity>(ProjectId);


                var query = Db.Queryable<ec_library_fileEntity>().AS(tableName)
                    .WhereIF(!string.IsNullOrEmpty(LibraryFileName), x => x.LibraryFileName.Contains(LibraryFileName))
                    .WhereIF(!string.IsNullOrEmpty(LibraryCatalogueID), x => x.LibraryCatalogueID == LibraryCatalogueID)
                    .WhereIF(!string.IsNullOrEmpty(LibraryFileNameFull), x => x.LibraryFileName == LibraryFileNameFull)
                    .WhereIF(!string.IsNullOrEmpty(ObjectTypeID), x => x.LibraryFileID == 
                    SqlFunc.Subqueryable<ec_objecttypelibEntity>().AS(libTableName).Where(y => y.ObjectTypeID == ObjectTypeID)
                    .GroupBy(y => y.LibraryFileID).Select(y => y.LibraryFileID))
                    .OrderByDescending(x => x.CreateTime);
                List<ec_library_fileEntity> list;
                if (pagination == null)
                {
                    list = query.ToList();
                }
                else
                {
                    list = query.ToPageList(pagination.page, pagination.rows);
                }
                var users = Db.Queryable<UserEntity>().ToList();
                list?.ForEach(x =>
                {
                    x.CreateUserName = users.FirstOrDefault(y => y.F_UserId == x.CreateUserID)?.F_RealName;
                });
                return list;
            }
            catch (Exception ex)
            {
                if (ex is ExceptionEx)
                {
                    throw;
                }
                else
                {
                    throw ExceptionEx.ThrowBusinessException(ex);
                }
            }
        }
        /// <summary>
        /// 获取实体数据
        /// <param name="keyValue">主键</param>
        /// <summary>
        /// <returns></returns>
        public ec_library_fileEntity GetEntity(string keyValue, string ProjectId)
        {
            try
            {
                return ec_library_fileService.GetEntity(keyValue, ProjectId);
            }
            catch (Exception ex)
            {
                if (ex is ExceptionEx)
                {
                    throw;
                }
                else
                {
                    throw ExceptionEx.ThrowBusinessException(ex);
                }
            }
        }

        #endregion

        #region 提交数据

        /// <summary>
        /// 删除实体数据
        /// <param name="keyValue">主键</param>
        /// <summary>
        /// <returns></returns>
        public void DeleteEntity(string keyValue, string ProjectId)
        {
            try
            {
                ec_library_fileService.DeleteEntity(keyValue, ProjectId);
            }
            catch (Exception ex)
            {
                if (ex is ExceptionEx)
                {
                    throw;
                }
                else
                {
                    throw ExceptionEx.ThrowBusinessException(ex);
                }
            }
        }

        /// <summary>
        /// 保存实体数据（新增、修改）
        /// <param name="keyValue">主键</param>
        /// <summary>
        /// <returns></returns>
        public void SaveEntity(string keyValue, ec_library_fileEntity entity, string ProjectId)
        {
            try
            {
                var fileList = new AnnexesFileBLL().GetList(entity.FolderId).ToList();
                if (fileList != null && fileList.Count > 0)
                {
                    if (!string.IsNullOrWhiteSpace(fileList[0].F_FilePath))
                    {
                        entity.FileMD5 = GetMD5HashFromFile(fileList[0].F_FilePath);
                    }
                }
                ec_library_fileService.SaveEntity(keyValue, entity, ProjectId);
            }
            catch (Exception ex)
            {
                if (ex is ExceptionEx)
                {
                    throw;
                }
                else
                {
                    throw ExceptionEx.ThrowBusinessException(ex);
                }
            }
        }
        /// <summary>
        /// 获取文件MD5值
        /// </summary>
        /// <param name="file">文件绝对路径</param>
        /// <returns>MD5值</returns>
        public static string GetMD5HashFromFile(string file)
        {
            try
            {
                FileStream fileStream = new FileStream(file, FileMode.Open, FileAccess.Read);
                System.Security.Cryptography.MD5 md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
                byte[] retVal = md5.ComputeHash(fileStream);
                fileStream.Close();
                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < retVal.Length; i++)
                {
                    sb.Append(retVal[i].ToString("x2"));
                }
                return sb.ToString();
            }
            catch (Exception ex)
            {
                throw new Exception("GetMD5HashFromFile() fail,error:" + ex.Message);
            }
        }

        /// <summary>
        /// 批量导入数据
        /// <param name="fileId">文件主键</param>
        /// <summary>
        /// <returns></returns>
        public void MuliteImport(string fileId, string ProjectId)
        {
            //获取附件信息
            var file = new AnnexesFileBLL().GetByfolderIdEntity(fileId);
            if (!string.IsNullOrWhiteSpace(file?.F_FilePath))
            {
                string virtualPath = string.Format("{0}/{1}/{2}/{3}/{4}", Config.GetValue("AnnexesFile"), "Decompress", LoginUserInfo.Get().userId, DateTime.Now.ToString("yyyyMMdd"), Guid.NewGuid().ToString("D"));
                string FileEextension = Path.GetExtension(file.F_FileName);//文件名后缀
                //如果解压目录不存在则创建
                if (!Directory.Exists(virtualPath))
                {
                    Directory.CreateDirectory(virtualPath);
                }
                var listLibraryCatalogu = new ec_library_catalogueService().GetList("{ProjectId:\"" + ProjectId + "\"}").ToList();
                CatalogAndFile catalogAndFile = new CatalogAndFile();
                catalogAndFile.FileEntities = new List<ec_library_fileEntity>();
                catalogAndFile.annexesFileEntities = new List<AnnexesFileEntity>();
                if (FileEextension.ToLower() == ".zip")
                {
                    catalogAndFile = Decompress(virtualPath, file.F_FilePath, catalogAndFile, listLibraryCatalogu);
                }
                else if (FileEextension.ToLower() == ".rar")
                {
                    catalogAndFile = DeCompressRar(virtualPath, file.F_FilePath, catalogAndFile, listLibraryCatalogu);
                }
                List<ec_library_fileEntity> addFileEntities = new List<ec_library_fileEntity>();
                List<ec_library_fileEntity> updateFileEntities = new List<ec_library_fileEntity>();
                //覆盖已经存在的元件库
                var listAllLibraryFile = GetList("{ProjectId:\"" + ProjectId + "\"}").ToList();
                foreach (var item in catalogAndFile.FileEntities)
                {
                    List<ec_library_fileEntity> tmpFileEntities = listAllLibraryFile.Where(x => x.LibraryCatalogueID == item.LibraryCatalogueID && x.LibraryFileName == item.LibraryFileName).ToList();
                    if (tmpFileEntities != null && tmpFileEntities.Count > 0)
                    {
                        foreach (var itemUpdate in tmpFileEntities)
                        {
                            itemUpdate.FolderId = item.FolderId;
                            itemUpdate.FileMD5 = item.FileMD5;
                            itemUpdate.UpdateUserID = item.CreateUserID;
                            itemUpdate.UpdateTime = item.CreateTime;
                            updateFileEntities.Add(itemUpdate);
                        }
                    }
                    else
                    {
                        addFileEntities.Add(item);
                    }
                }
                //更新数据
                ec_library_fileService.MuliteImport(addFileEntities, updateFileEntities, catalogAndFile.annexesFileEntities, ProjectId);
            }
        }
        /// <summary>
        /// 修改集合数据,新增附件数据集合
        /// <summary>
        /// <returns></returns>
        public void SaveDataAndAnnexes(string ProjectId)
        {
            try
            {
                UserInfo userInfo = LoginUserInfo.Get();
                List<AnnexesFileEntity> listAnnexesFile = new List<AnnexesFileEntity>();
                var libraryFileData = GetList("{ProjectId:\"" + ProjectId + "\"}").ToList();
                foreach (var item in libraryFileData)
                {
                    var fileList = new AnnexesFileService().GetList(item.FolderId).ToList();
                    item.FolderId = Guid.NewGuid().ToString();
                    for (var i = 0; i < fileList.Count; i++)
                    {
                        if (i == 0 && !string.IsNullOrWhiteSpace(fileList[0].F_FilePath))
                        {
                            if (System.IO.File.Exists(fileList[0].F_FilePath))
                            {
                                item.FileMD5 = GetMD5HashFromFile(fileList[0].F_FilePath);
                            }
                        }
                        fileList[i].F_Id = Guid.NewGuid().ToString();
                        fileList[i].F_FolderId = item.FolderId;
                        fileList[i].F_CreateDate = Time.MySqlTime;
                        fileList[i].F_CreateUserId = userInfo.userId;
                        fileList[i].F_CreateUserName = userInfo.realName;
                        listAnnexesFile.Add(fileList[i]);
                    }
                }
                ec_library_fileService.SaveDataAndAnnexes(libraryFileData, listAnnexesFile, ProjectId);
            }
            catch (Exception ex)
            {
                if (ex is ExceptionEx)
                {
                    throw;
                }
                else
                {
                    throw ExceptionEx.ThrowBusinessException(ex);
                }
            }
        }

        #endregion
        #region 解压缩文件
        /// <summary>
        /// 解压zip格式的文件
        /// </summary>
        /// <param name="unZipDir">解压文件存放路径</param>
        /// <param name="zipFilePath">压缩文件路径</param>
        /// <param name="catalogAndFile">导入的文件数据</param>
        /// <param name="listLibraryCatalogu">已有目录数据</param>
        /// <returns></returns>
        public CatalogAndFile Decompress(string unZipDir, string zipFilePath, CatalogAndFile catalogAndFile, List<ec_library_catalogueEntity> listLibraryCatalogu)
        {
            UserInfo userInfo = LoginUserInfo.Get();
            if (!Directory.Exists(unZipDir))
                Directory.CreateDirectory(unZipDir);//生成解压目录  
            byte[] data = new byte[2048];
            int size = 2048;
            //一个ZIP文件中的条目，可以理解为压缩包里面的一个文件夹/文件
            ZipEntry theEntry = null;
            string fileCatalogID = "";
            //解压缩输出流，从压缩包中一个接一个的读出文档。
            using (ZipInputStream inputStream = new ZipInputStream(File.OpenRead(zipFilePath)))
            {
                while ((theEntry = inputStream.GetNextEntry()) != null)
                {
                    if (theEntry.IsDirectory)
                    {
                        // 该结点是目录    
                        if (!Directory.Exists(unZipDir + "/" + theEntry.Name))
                        {
                            Directory.CreateDirectory(unZipDir + "/" + theEntry.Name);
                        }

                    }
                    else
                    {
                        //获取目录名称
                        string strPath = theEntry.Name.Substring(0, theEntry.Name.LastIndexOf('/') + 1);
                        var temCatalog = listLibraryCatalogu.Find(x => x.FullPathCN == strPath.TrimEnd('/'));
                        fileCatalogID = temCatalog == null ? "" : temCatalog.LibraryCatalogueID;
                        if (!string.IsNullOrEmpty(fileCatalogID) && !string.IsNullOrEmpty(theEntry.Name))
                        {
                            string fileName = Path.Combine(unZipDir, theEntry.Name);
                            using (FileStream streamWriter = File.Create(fileName))
                            {
                                while (true)
                                {
                                    size = inputStream.Read(data, 0, data.Length);
                                    if (size <= 0) break;
                                    streamWriter.Write(data, 0, size);
                                }
                                streamWriter.Close();
                            }
                            fileName = fileName.Replace('\\', '/');
                            //保存要插入的元件库文件实体
                            ec_library_fileEntity file = new ec_library_fileEntity();
                            file.Create();
                            file.LibraryFileName = Path.GetFileName(fileName);
                            file.LibraryCatalogueID = fileCatalogID;
                            file.FileMD5 = GetMD5HashFromFile(fileName);
                            file.FolderId = Guid.NewGuid().ToString();
                            catalogAndFile.FileEntities.Add(file);

                            AnnexesFileEntity annexesFiles = new AnnexesFileEntity();
                            annexesFiles.F_Id = Guid.NewGuid().ToString();
                            annexesFiles.F_FolderId = file.FolderId;
                            annexesFiles.F_CreateDate = Time.MySqlTime;
                            annexesFiles.F_FileName = file.LibraryFileName;
                            annexesFiles.F_FilePath = fileName;
                            annexesFiles.F_FileSize = theEntry.Size.ToString();
                            annexesFiles.F_FileExtensions = Path.GetExtension(fileName);
                            annexesFiles.F_FileType = annexesFiles.F_FileExtensions.TrimStart('.');
                            annexesFiles.F_CreateUserId = userInfo.userId;
                            annexesFiles.F_CreateUserName = userInfo.realName;
                            catalogAndFile.annexesFileEntities.Add(annexesFiles);
                        }
                    }
                }
                inputStream.Close();
            }
            return catalogAndFile;
        }

        /// <summary>
        /// 获取winrar的安装位置
        /// </summary>
        /// <returns></returns>
        public static string ExistsWinRar()
        {
            string result = string.Empty;
            string key = @"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\WinRAR.exe";
            RegistryKey registryKey = Registry.LocalMachine.OpenSubKey(key);
            if (registryKey != null)
            {
                result = registryKey.GetValue("").ToString();
                registryKey.Close();
            }
            return result;

        }
        /// <summary>
        /// 将格式为rar的压缩文件解压到指定的目录
        /// </summary>
        /// <param name="unZipDir">解压后要保存到的目录</param>
        /// <param name="zipFilePath">要解压rar文件的路径</param>
        /// <param name="catalogAndFile">导入的文件数据</param>
        /// <param name="listLibraryCatalogu">已有目录数据</param>
        ///  <returns></returns>
        public CatalogAndFile DeCompressRar(string unZipDir, string zipFilePath, CatalogAndFile catalogAndFile, List<ec_library_catalogueEntity> listLibraryCatalogu)
        {
            UserInfo userInfo = LoginUserInfo.Get();
            var compressFiles = new List<FileInfo>();
            string winrarPath = ExistsWinRar();
            if (!string.IsNullOrEmpty(winrarPath))
            {
                if (!Directory.Exists(unZipDir))
                    Directory.CreateDirectory(unZipDir);//生成解压目录  
                string winrarDir = Path.GetDirectoryName(winrarPath);
                string commandOptions = string.Format("x {0} {1} -y", zipFilePath, unZipDir);
                ProcessStartInfo processStartInfo = new ProcessStartInfo();
                processStartInfo.FileName = Path.Combine(winrarDir, "rar.exe");
                processStartInfo.Arguments = commandOptions;
                processStartInfo.WindowStyle = ProcessWindowStyle.Hidden;

                Process process = new Process();
                process.StartInfo = processStartInfo;
                process.StartInfo.UseShellExecute = false;
                process.StartInfo.CreateNoWindow = true;
                process.Start();
                var files = 0;
                while (process.HasExited)
                {
                    files++;
                }
                process.WaitForExit();
                process.Close();
                var dir = new DirectoryInfo(unZipDir);
                FindDirAndFile(dir, compressFiles);
                for (int i = 0; i < compressFiles.Count; i++)
                {
                    //保存要插入的元件库文件实体
                    ec_library_fileEntity file = new ec_library_fileEntity();
                    file.Create();
                    file.LibraryFileName = compressFiles[i].Name;
                    string DirectoryName = compressFiles[i].DirectoryName.Replace('\\', '/');
                    DirectoryName = DirectoryName.Replace(unZipDir + "/", "");
                    var temCatalog = listLibraryCatalogu.Find(x => x.FullPathCN == DirectoryName);
                    string fileCatalogID = temCatalog == null ? "" : temCatalog.LibraryCatalogueID;
                    if (string.IsNullOrEmpty(fileCatalogID))
                    {
                        continue;
                    }
                    file.LibraryCatalogueID = fileCatalogID;
                    file.FileMD5 = GetMD5HashFromFile(compressFiles[i].FullName);
                    file.FolderId = Guid.NewGuid().ToString();
                    catalogAndFile.FileEntities.Add(file);

                    AnnexesFileEntity annexesFiles = new AnnexesFileEntity();
                    annexesFiles.F_Id = Guid.NewGuid().ToString();
                    annexesFiles.F_FolderId = file.FolderId;
                    annexesFiles.F_CreateDate = Time.MySqlTime;
                    annexesFiles.F_FileName = file.LibraryFileName;
                    annexesFiles.F_FilePath = compressFiles[i].FullName;
                    annexesFiles.F_FileSize = compressFiles[i].Length.ToString();
                    annexesFiles.F_FileExtensions = Path.GetExtension(compressFiles[i].FullName);
                    annexesFiles.F_FileType = annexesFiles.F_FileExtensions.TrimStart('.');
                    annexesFiles.F_CreateUserId = userInfo.userId;
                    annexesFiles.F_CreateUserName = userInfo.realName;
                    catalogAndFile.annexesFileEntities.Add(annexesFiles);
                }
            }
            else
            {
                //message = "请先安装winrar程序，再上传文件";
            }
            return catalogAndFile;
        }

        //查找所有目录和文件
        public void FindDirAndFile(DirectoryInfo di, List<FileInfo> files)
        {
            FileInfo[] fis = di.GetFiles();
            files.AddRange(fis);
            DirectoryInfo[] dis = di.GetDirectories();
            for (int j = 0; j < dis.Length; j++)
            {
                FindDirAndFile(dis[j], files);
            }
        }

        /// <summary>
        /// 存放压缩文件里面的目录和文件
        /// </summary>
        public class CatalogAndFile
        {
            /// <summary>
            /// 元件库文件集合
            /// </summary>
            public List<ec_library_fileEntity> FileEntities { get; set; }
            /// <summary>
            /// 附件集合
            /// </summary>
            public List<AnnexesFileEntity> annexesFileEntities { get; set; }
        }
        #endregion


    }
}
